package com.joolun.web.controller.weixin;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.joolun.common.annotation.Anonymous;
import com.joolun.common.core.domain.AjaxResult;
import com.joolun.common.core.redis.RedisCache;
import com.joolun.common.utils.ip.IpUtils;
import com.joolun.system.domain.EduCourse;
import com.joolun.system.domain.PayLink;
import com.joolun.system.domain.ScrmCustomerInfo;
import com.joolun.system.service.IEduCourseService;
import com.joolun.weixin.entity.WxUser;
import com.joolun.weixin.entity.dto.LoginWxMpDTO;
import com.joolun.weixin.entity.vo.WxLoginVo;
import com.joolun.weixin.service.IScrmCustomerInfoService;
import com.joolun.weixin.service.WxUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Binary Wang(https://github.com/binarywang)
 */
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/weixin/portal/{appid}")
public class WxPortalController {
    private final WxMpService wxService;
    private final WxMpMessageRouter messageRouter;

    private final WxUserService wxUserService;

    @Autowired
    private IScrmCustomerInfoService scrmCustomerInfoService;

    @Autowired
    private IEduCourseService iEduCourseService;

    @Autowired
    private RedisCache redisCache;

    @GetMapping(produces = "text/plain;charset=utf-8")
    @Anonymous
    public String authGet(@PathVariable String appid,
                          @RequestParam(name = "signature", required = false) String signature,
                          @RequestParam(name = "timestamp", required = false) String timestamp,
                          @RequestParam(name = "nonce", required = false) String nonce,
                          @RequestParam(name = "echostr", required = false) String echostr) {

        log.info("\n接收到来自微信公众号服务器的认证消息：[{}, {}, {}, {}]", signature,
            timestamp, nonce, echostr);
        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法，请核实!");
        }

        if (!this.wxService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }

        if (wxService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }

        return "非法请求";
    }

    @PostMapping(produces = "application/xml; charset=UTF-8")
    @Anonymous
    public String post(@PathVariable String appid,
                       @RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam("openid") String openid,
                       @RequestParam(name = "encrypt_type", required = false) String encType,
                       @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        log.info("\n接收微信公众号请求：[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
                + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
            openid, signature, encType, msgSignature, timestamp, nonce, requestBody);

        if (!this.wxService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }

        if (!wxService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        String out = null;
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toXml();
        } else if ("aes".equalsIgnoreCase(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
                timestamp, nonce, msgSignature);
            log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
        }

        log.debug("\n组装回复信息：{}", out);
        return out;
    }

    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.messageRouter.route(message);
        } catch (Exception e) {
            log.error("路由消息时出现异常！", e);
        }

        return null;
    }

    /**
     * 微信公众号登录
     *
     * @param request JSON格式参数
     * @return RestResponse
     */
    @PostMapping("loginByMp")
    @Anonymous
    //@ApiOperation("微信公众号登录")
    public AjaxResult<WxLoginVo> loginByMp(@RequestBody LoginWxMpDTO request) {
        String code = request.getCode();
        String mpAppId = request.getMpAppId();

        // TODO:参数校验不能为空
        if (!wxService.switchover(mpAppId)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", mpAppId));
        }

        WxLoginVo wxLoginVo = new WxLoginVo();
        try {
            WxOAuth2AccessToken auth2AccessToken = wxService.getOAuth2Service().getAccessToken(code);
            log.info("---公众号登录授权返回：{}", JSON.toJSONString(auth2AccessToken));

            String openId = auth2AccessToken.getOpenId();
            //获取微信用户信息
            WxOAuth2UserInfo wxMpUser = wxService.getOAuth2Service().getUserInfo(auth2AccessToken, null);
            log.info("---获取公众号用户信息：{}", JSON.toJSONString(wxMpUser));
            //保存或者更新
            WxUser user = wxUserService.getOne(new QueryWrapper<WxUser>().eq("union_id", wxMpUser.getUnionId()));
            if (user == null) {
                user = wxUserService.getOne(new QueryWrapper<WxUser>().eq("open_id", wxMpUser.getOpenid()));
            }
            String ip = IpUtils.getIpAddr();
            System.out.println("-------------注册IP--------" + ip);
            // 没有数据即新注册用户
            if (user == null) {
                user = new WxUser();
                // 新用户，设置创建ip
                user.setAddressIp(ip);
            }
           // user.setSubscribeTime(new Date());
            user.setUnionId(wxMpUser.getUnionId());
            user.setOpenId(wxMpUser.getOpenid());
            user.setNickName(wxMpUser.getNickname());
            user.setHeadimgUrl(wxMpUser.getHeadImgUrl());

            Boolean subscribe = wxService.getUserService().userInfo(openId).getSubscribe();
            // 是否关注
            user.setSubscribe(subscribe.equals(true)?"1":"0");
            wxUserService.saveOrUpdate(user);

            //生成token
            //String token = jwtUtils.generateToken(user.getId());
            // String token2 = tokenService.createWxToken(user);

            //wxLoginVo.setToken(token);
            wxLoginVo.setWxUser(user);
            wxLoginVo.setUserId(user.getId());

        } catch (WxErrorException e) {
            log.error("登录失败：" + e.getMessage());
            return AjaxResult.error("登录失败，请联系班主任");
        } catch (NumberFormatException  e) {
            log.error("course地址不正确：" + e.getMessage());
            return AjaxResult.error("课程地址不正确，请联系班主任");
        }
        return AjaxResult.success(wxLoginVo);
    }

    /**
     * 微信公众号登录,直播授权
     *
     * @param request JSON格式参数
     * @return RestResponse
     */
    @PostMapping("loginByZb")
    @Anonymous
    //@ApiOperation("微信公众号登录")
    public AjaxResult<WxLoginVo> loginByZb(@RequestBody LoginWxMpDTO request) {
        String code = request.getCode();
        String mpAppId = request.getMpAppId();

        // TODO:参数校验不能为空
        if (!wxService.switchover(mpAppId)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", mpAppId));
        }

        WxLoginVo wxLoginVo = new WxLoginVo();
        try {
            WxOAuth2AccessToken auth2AccessToken = wxService.getOAuth2Service().getAccessToken(code);
            log.info("---公众号登录授权返回：{}", JSON.toJSONString(auth2AccessToken));

            String openId = auth2AccessToken.getOpenId();
            //获取微信用户信息
            WxOAuth2UserInfo wxMpUser = wxService.getOAuth2Service().getUserInfo(auth2AccessToken, null);
            log.info("---获取公众号用户信息：{}", JSON.toJSONString(wxMpUser));
            //保存或者更新
            WxUser user = wxUserService.getOne(new QueryWrapper<WxUser>().eq("union_id", wxMpUser.getUnionId()));
            if (user == null) {
                user = wxUserService.getOne(new QueryWrapper<WxUser>().eq("open_id", wxMpUser.getOpenid()));
            }
            String ip = IpUtils.getIpAddr();
            System.out.println("-------------注册IP--------" + ip);
            // 没有数据即新注册用户
            if (user == null) {
                user = new WxUser();
                // 新用户，设置创建ip
                user.setAddressIp(ip);
            }
            // user.setSubscribeTime(new Date());
            user.setUnionId(wxMpUser.getUnionId());
            user.setOpenId(wxMpUser.getOpenid());
            user.setNickName(wxMpUser.getNickname());
            user.setHeadimgUrl(wxMpUser.getHeadImgUrl());

            Boolean subscribe = wxService.getUserService().userInfo(openId).getSubscribe();
            // 是否关注
            user.setSubscribe(subscribe.equals(true)?"1":"0");

            wxUserService.saveOrUpdate(user);

            //生成token
            //String token = jwtUtils.generateToken(user.getId());
            // String token2 = tokenService.createWxToken(user);

            //wxLoginVo.setToken(token);
            wxLoginVo.setWxUser(user);
            wxLoginVo.setUserId(user.getId());
            // 移动端
            wxLoginVo.setIsAppOrWeb("app");
            // 获取用户信息，返回验证用户是否具有观看权限
            ScrmCustomerInfo scrmCustomerInfo = scrmCustomerInfoService.getOne(Wrappers.lambdaQuery(ScrmCustomerInfo.class)
                    .eq(ScrmCustomerInfo::getUnionId,user.getUnionId())
                    .orderByDesc(ScrmCustomerInfo::getId) // 按 id 降序排序（大的在前）
                    .last("LIMIT 1") // 只取第一条（ID 最大的那条）
            );
            System.out.println("------------------------------scrmCustomerInfo----------------------------:" + scrmCustomerInfo);
            String courseId = request.getCourseId();
            System.out.println("------------------------------courseId----------------------------:" + courseId);
            wxLoginVo.setIsCustomerInfo("course");
            if(scrmCustomerInfo != null){
                if(courseId != null && courseId != ""){
                    EduCourse eduCourse = iEduCourseService.selectEduCourseByCourseId(Long.parseLong(courseId));
                    if(eduCourse != null){
                        // 用户的权限大于课程权限，即表示具有观看权限，否则无权限
                        if(scrmCustomerInfo.getCoursePermission() >= eduCourse.getCourseType1()){
                            wxLoginVo.setIsCustomerInfo("open");
                            System.out.println("open----------------------授权成功");
                            String uuid = request.getUuid();
                            System.out.println("----------------------------------------------------------uuid:" + uuid);
                            // uuid = 2 表示公众号授权，不做任何操作，如果用户第一次授权，则将用户信息入库
                            // uuid = 0 表示直播手机端授权, 授权后手机端直接跳转直播界面
                            // uuid 长度大于1 表示直播电脑端授权，此时将用户缓存到redis，电脑端接收到用户授权信息，电脑端跳转直播界面
                            if(uuid != null && uuid.length() > 1){
                                Boolean isEwm = redisCache.getCacheObject(uuid + "uuid");
                                System.out.println("----------------------isEwm：" + isEwm);
                                if(isEwm != null && isEwm){
                                    // web端
                                    wxLoginVo.setIsAppOrWeb("web");
                                    // 将uuid对应的授权用户存入redis,设置1分钟有效期
                                    redisCache.setCacheObject(uuid, user,1, TimeUnit.MINUTES);
                                }else{
                                    wxLoginVo.setIsCustomerInfo("out");
                                    System.out.println("out----------------------二维码已过期");
                                }
                            }
                        }else{
                            wxLoginVo.setIsCustomerInfo("close");
                            System.out.println("close----------------------无权限");
                        }
                    }else{
                        return AjaxResult.error("课程地址不正确，请联系班主任");
                    }
                }else{
                    return AjaxResult.error("课程地址不正确，请联系班主任");
                }
            }else{
                return AjaxResult.error("不是企微客户，请联系班主任");
            }
        } catch (WxErrorException e) {
            log.error("登录失败：" + e.getMessage());
            return AjaxResult.error("登录失败，请联系班主任");
        } catch (NumberFormatException  e) {
            log.error("course地址不正确：" + e.getMessage());
            return AjaxResult.error("课程地址不正确，请联系班主任");
        }
        return AjaxResult.success(wxLoginVo);
    }

}
